Skip to content

Conversation

@Stuart-Mouse
Copy link

This is still a bit of a draft, but here's a working proposal for type handlers that allow user extension of the parser. Some work would still need to be done for serialization. Let me know what you think.

Also, here is a sample program demonstrating how these type handlers can be implemented by the user. As the example shows, this gives the user the option of either going the more dynamic route with a generalized hash table handler, or the code generation route, generating specific handlers for each table type.

#import "Basic";
#import "Hash_Table";
#import "Any_Hash_Table";
#import "jaison";

main :: () {
    Foo :: struct {
        _int: int;
        _float: float;
        _string: string;
    }
    
    TABLE_TYPE :: Table(string, Foo);
    
    // array_add(*context.jaison.type_handlers, get_generic_table_handler());
    array_add(*context.jaison.type_handlers, get_specific_table_handler(TABLE_TYPE));
    
    ok, table := json_parse_string(FILE, TABLE_TYPE);
    if ok  for table  log("%: %", it_index, it);
    else log("failed to parse json");
}

FILE :: #string JSON
{
    "key1": { "_int": 1, "_float": 1.1, "_string": "str1" },
    "key2": { "_int": 2, "_float": 2.2, "_string": "str2" },
    "key3": { "_int": 3, "_float": 3.3, "_string": "str3" }
}
JSON;


get_generic_table_handler :: () -> JSON_Type_Handler {
    return .{
        type = type_info(Table(*void, *void)).polymorph_source_struct,
        
        prepare_slot = (handler: *JSON_Type_Handler, expected_type: Type_Info_Tag, info: *Type_Info, slot: *void) -> success: bool, info: *Type_Info, slot: *void {
            if expected_type != .STRUCT {
                return false, null, null;
            }
            
            any_table := New(Any_Table);
            any_table.* = Any_Table.from(Any.{ info, slot });
            handler.user_data = any_table;
            
            // TODO: log error and return false if key type is not string
            return true, info, slot;
        },
        
        get_member_slot = (handler: *JSON_Type_Handler, info: *Type_Info, slot: *void, key: string, index: int) -> success: bool, info: *Type_Info, slot: *void {
            table := cast(*Any_Table) handler.user_data;
            value_any := table_set(table, key, Any.{ type = table.value_type });
            return true, value_any.type, value_any.value_pointer;
        },
        
        deinit = (handler: *JSON_Type_Handler) {
            free(handler.user_data);
        },
    };
};

get_specific_table_handler :: ($T: Type) -> JSON_Type_Handler #modify {
    struct_info := cast(*Type_Info_Struct) T;
    if struct_info.type != .STRUCT 
    && struct_info.polymorph_source_struct != type_info(Table(*void, *void)).polymorph_source_struct {
        return false, "T must be a Table where Key_Type = string.";
    }
    return true;
} {
    #assert T.Key_Type == string;
    return .{
        type = xx T,
        
        prepare_slot = (handler: *JSON_Type_Handler, expected_type: Type_Info_Tag, info: *Type_Info, slot: *void) -> success: bool, info: *Type_Info, slot: *void {
            if expected_type != .STRUCT {
                return false, null, null;
            }
            return true, info, slot;
        },
        
        get_member_slot = (handler: *JSON_Type_Handler, info: *Type_Info, slot: *void, key: string, index: int) -> success: bool, info: *Type_Info, slot: *void {
            table := cast(*T) slot;
            dummy_value_to_insert: T.Value_Type;
            value_pointer := table_set(table, key, dummy_value_to_insert);
            return true, xx table.Value_Type, value_pointer;
        },
    };
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants